home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Sprite 1984 - 1993
/
Sprite 1984 - 1993.iso
/
src
/
kernel
/
net
/
sun4.md
/
netUltra.c
< prev
Wrap
C/C++ Source or Header
|
1992-12-18
|
89KB
|
3,040 lines
/*
* netUltra.c --
*
* Routines for handling the Ultranet VME Adapter card..
*
* Copyright 1990 Regents of the University of California
* Permission to use, copy, modify, and distribute this
* software and its documentation for any purpose and without
* fee is hereby granted, provided that the above copyright
* notice appear in all copies. The University of California
* makes no representations about the suitability of this
* software for any purpose. It is provided "as is" without
* express or implied warranty.
*/
#ifndef lint
static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/net/sun4.md/netUltra.c,v 1.7 92/04/14 22:34:08 jhh Exp $ SPRITE (Berkeley)";
#endif /* not lint */
#include <sprite.h>
#include <vm.h>
#include <vmMach.h>
#include <mach.h>
#include <netUltraInt.h>
#include <dev/ultra.h>
#include <fmt.h>
#include <sync.h>
#include <dbg.h>
#include <rpcPacket.h>
#include <assert.h>
/*
* "Borrow" the Vax format for the format of the Ultranet adapter (it
* is really a 386. We need to swap some of the words in the
* diagnostic and information structures.
*/
#define NET_ULTRA_FORMAT FMT_VAX_FORMAT
Boolean netUltraDebug = FALSE;
Boolean netUltraTrace = TRUE;
int netUltraMapThreshold = NET_ULTRA_MAP_THRESHOLD;
static int packetsSunk = 0;
static Time sinkStartTime;
static Time sinkEndTime;
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define WAIT_FOR_REPLY(ptr, count) { \
int i; \
for(i = (count); i > 0; i -= 100) { \
MACH_DELAY(100); \
if (*((volatile int *)ptr) != 0) { \
break; \
} \
} \
}
/*
* The following are the names of the diagnostic tests as listed in the
* uvm man page provided in the Ultranet documentation.
*/
static char *diagNames[] = {
"EPROM checksum",
"Abbreviated RAM check",
"Interrupt controller and interval timer",
"Internal loopback",
"FIFO RAM check",
"Checksum gate arrays",
"NMI control logic"
};
/*
* The following are the names of the extended diagnostic tests as
* listed in the uvm man page.
*/
static char *extDiagNames[] = {
"EPROM checksum",
"Full RAM check",
"Interrupt controller and interval timer",
"Internal or external loopback",
"FIFO RAM check",
"Checksum gate arrays",
"NMI control logic",
"DMA to hosts memory using VME bus",
"Extended FIFO RAM check",
"FIFO Control logic"
};
/*
* This is a "wildcard" address that matches any TL address.
* Once again we have to lie about the size of a Net_Address
* since the adapter will puke if it isn't 7 bytes (why have it
* if you can't change it?).
*/
static Net_UltraTLAddress wildcardAddress =
{7, NET_ULTRA_TSAP_SIZE};
/*
* Forward declarations.
*/
static Sync_Condition dsndTestDone;
static int dsndCount;
static char *GetStatusString _ARGS_ ((int status));
static void InitQueues _ARGS_((NetUltraState *statePtr));
static void StandardDone _ARGS_((Net_Interface *interPtr,
NetUltraXRBInfo *infoPtr));
static void ReadDone _ARGS_((Net_Interface *interPtr,
NetUltraXRBInfo *infoPtr));
static void EchoDone _ARGS_((Net_Interface *interPtr,
NetUltraXRBInfo *infoPtr));
static ReturnStatus NetUltraSendDgram _ARGS_((Net_Interface *interPtr,
Net_Address *netAddressPtr, int count,
int bufSize, Address buffer, Time *timePtr));
static void DgramSendDone _ARGS_((Net_Interface *interPtr,
NetUltraXRBInfo *infoPtr));
static void OutputDone _ARGS_((Net_Interface *interPtr,
NetUltraXRBInfo *infoPtr));
static void SourceDone _ARGS_((Net_Interface *interPtr,
NetUltraXRBInfo *infoPtr));
static ReturnStatus NetUltraSource _ARGS_((Net_Interface *interPtr,
Net_Address *netAddressPtr, int count,
int bufSize, Address buffer, Time *timePtr));
static void NetUltraResetCallback _ARGS_((ClientData data,
Proc_CallInfo *infoPtr));
/*
* Macros for mapping between kernel, DVMA and VME addresses.
*/
#define DVMA_TO_BUFFER(addr, statePtr) \
((Address) (((((unsigned int) (addr)) - \
((unsigned int) (statePtr)->buffersDVMA)) + \
((int) (statePtr)->buffers))))
#define BUFFER_TO_DVMA(addr, statePtr) \
((Address) ((((unsigned int) (addr)) - \
((unsigned int) (statePtr)->buffers)) + \
((unsigned int) (statePtr)->buffersDVMA)))
#define DVMA_TO_VME(addr, statePtr) \
((Address) (((unsigned int) (addr)) - \
((unsigned int) VMMACH_DMA_START_ADDR)))
#define VME_TO_DVMA(addr, statePtr) \
((Address) (((unsigned int) (addr)) + \
((unsigned int) VMMACH_DMA_START_ADDR)))
#define BUFFER_TO_VME(addr, statePtr) \
((Address) (DVMA_TO_VME(BUFFER_TO_DVMA(addr,statePtr), (statePtr))))
#define VME_TO_BUFFER(addr, statePtr) \
((Address) (DVMA_TO_BUFFER(VME_TO_DVMA((addr),statePtr),(statePtr))))
#define DVMA_ADDRESS(addr, statePtr) \
((unsigned int) (addr) < ((unsigned int)VMMACH_DMA_START_ADDR)? FALSE :TRUE)
/*
*----------------------------------------------------------------------
*
* NetUltraInit --
*
* Initialize the Ultranet VME adapter card.
*
* Results:
* SUCCESS if the Ultranet card was found and initialized.
* FAILURE otherwise.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraInit(interPtr)
Net_Interface *interPtr; /* Network interface. */
{
unsigned int ctrlAddr;
NetUltraState *statePtr;
ReturnStatus status = SUCCESS;
int zero = 0;
NetUltraExtDiagCommand extDiagCmd;
NetUltraInfoCommand infoCmd;
char *buffer;
/*
* Make sure that we agree with the adapter as to the size of the
* command blocks and other structures.
*/
assert(sizeof(Net_UltraAddress) == 8);
assert(sizeof(Net_UltraTLAddress) == 16);
assert(sizeof(Net_UltraHeader) == 56);
assert(sizeof(NetUltraDMAInfo) == 16);
assert(sizeof(NetUltraRequestHdr) == 16);
assert(sizeof(NetUltraDatagramRequest) == 56);
assert(sizeof(NetUltraStartRequest) == 112);
assert(sizeof(NetUltraStopRequest) == 16);
assert(sizeof(NetUltraRequest) == 112);
assert(sizeof(NetUltraXRB) == 132);
assert(sizeof(NetUltraInitCommand) == 64);
assert(sizeof(NetUltraDiagCommand) == 36);
assert(sizeof(NetUltraExtDiagCommand) == 24);
assert(sizeof(NetUltraLoadCommand) == 24);
assert(sizeof(NetUltraGoCommand) == 12);
assert(sizeof(Net_UltraHeader) == sizeof(NetUltraDatagramRequest));
ctrlAddr = (unsigned int) interPtr->ctrlAddr;
/*
* If the address is physical (not in kernel's virtual address space)
* then we have to map it in.
*/
if (interPtr->virtual == FALSE) {
ctrlAddr = (unsigned int) VmMach_MapInDevice((Address) ctrlAddr, 3);
}
statePtr = (NetUltraState *) malloc (sizeof(NetUltraState));
bzero((char *) statePtr, sizeof(NetUltraState));
/*
* The first register is the interrupt register, then
* the reset register, separated by 12 bytes.
*/
statePtr->intrReg = (int *) ctrlAddr;
statePtr->resetReg = (int *) (ctrlAddr + 0x10);
/*
* Now poke the reset register.
*/
status = Mach_Probe(sizeof(int), (char *) &zero,
(char *) statePtr->resetReg);
if (status != SUCCESS) {
/*
* Got a bus error.
*/
goto exit;
}
if (netUltraDebug) {
printf("NetUltraInit: adapter at 0x%x probed successfully\n",
statePtr->intrReg);
}
MACH_DELAY(NET_ULTRA_RESET_DELAY);
statePtr->magic = NET_ULTRA_STATE_MAGIC;
statePtr->flags = NET_ULTRA_STATE_EXIST | NET_ULTRA_STATE_EPROM |
NET_ULTRA_STATE_NORMAL;
statePtr->interPtr = interPtr;
interPtr->interfaceData = (ClientData) statePtr;
statePtr->tracePtr = statePtr->traceBuffer;
statePtr->traceSequence = 0;
/*
* Get the adapter information.
*/
status = NetUltraInfo(statePtr, &infoCmd);
if (status == SUCCESS) {
printf(
"UltraNet adapter %d.%d, Revision %d, Option %d, Firmware %d, Serial %d\n",
infoCmd.hwModel, infoCmd.hwVersion,
infoCmd.hwRevision, infoCmd.hwOption,
infoCmd.version, infoCmd.hwSerial);
if (infoCmd.error == 0) {
printf("Ultranet adapter passed all diagnostics.\n");
} else {
int tmp = infoCmd.error;
int i;
printf(
"Ultranet adapter failed diagnostics (0x%x).\n", tmp);
printf("The following tests failed:\n");
for (i = 0; i < sizeof(int) * 8; i++) {
if (tmp & 1) {
printf("%2d: %s\n", i+1, diagNames[i]);
}
tmp >>= 1;
}
status = FAILURE;
goto exit;
}
} else {
printf("NetUltraInit: unable to send info command to adapter\n");
goto exit;
}
/*
* Send an extended diagnostics command to the adapter.
*/
buffer = (char *) malloc(NET_ULTRA_EXT_DIAG_BUF_SIZE);
status = NetUltraExtDiag(statePtr, FALSE, buffer, &extDiagCmd);
free(buffer);
if (status == SUCCESS) {
if (extDiagCmd.error == 0) {
printf("Ultranet adapter passed all extended diagnostics.\n");
} else {
int tmp = extDiagCmd.error;
int i;
printf(
"Ultranet adapter failed extended diagnostics (0x%x).\n", tmp);
printf("The following tests failed:\n");
for (i = 0; i < sizeof(int) * 8; i++) {
if (tmp & 1) {
printf("%2d: %s\n", i+1, extDiagNames[i]);
}
tmp >>= 1;
}
status = FAILURE;
goto exit;
}
} else {
printf(
"NetUltraInit: unable to send extended diagnostics command to adapter\n");
goto exit;
}
interPtr->ctrlAddr = (Address) ctrlAddr;
statePtr->queuesInit = FALSE;
InitQueues(statePtr);
statePtr->priority = NET_ULTRA_INTERRUPT_PRIORITY;
statePtr->requestLevel = NET_ULTRA_VME_REQUEST_LEVEL;
statePtr->addressSpace = NET_ULTRA_VME_ADDRESS_SPACE;
Mach_SetHandler(interPtr->vector, Net_Intr, (ClientData) interPtr);
interPtr->init = NetUltraInit;
interPtr->intr = NetUltraIntr;
interPtr->ioctl = NetUltraIOControl;
interPtr->reset = Net_UltraReset;
interPtr->output = NetUltraOutput;
interPtr->netType = NET_NETWORK_ULTRA;
interPtr->maxBytes = NET_ULTRA_MAX_BYTES;
interPtr->minBytes = NET_ULTRA_MIN_BYTES;
if (sizeof(NetUltraXRB) != 132) {
printf("NetUltraInit: WARNING: NetUltraXRB is not 132 bytes!!!\n");
}
exit:
if (status != SUCCESS && statePtr != (NetUltraState *) NIL) {
free((char *) statePtr);
}
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraHardReset --
*
* Does a hard reset of the Ultranet adapter. This means the adapter
* board goes back to its state right after power-up -- no
* micro-code or anything.
*
* Results:
* SUCCESS if a reply was received properly, FAILURE otherwise
*
* Side effects:
* The ultranet adapter is initialized.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraHardReset(interPtr)
Net_Interface *interPtr; /* Interface to reset. */
{
NetUltraState *statePtr; /* State of the adapter. */
ReturnStatus status = SUCCESS;
int zero = 0;
statePtr = (NetUltraState *) interPtr->interfaceData;
printf("Ultra: adapter reset.\n");
status = Mach_Probe(sizeof(int), (char *) &zero,
(char *) statePtr->resetReg);
if (status != SUCCESS) {
/*
* Adapter is no longer responding.
*/
printf("NetUltraHardReset: adapter did not respond to reset!!\n");
statePtr->flags = 0;
return FAILURE;
}
MACH_DELAY(NET_ULTRA_RESET_DELAY);
InitQueues(statePtr);
/*
* After a reset the adapter is in the EPROM mode.
* This allows several additional commands (load, go, etc.) to be
* sent to the adapter.
*/
statePtr->flags = NET_ULTRA_STATE_EXIST | NET_ULTRA_STATE_EPROM;
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraInitAdapter --
*
* Allocate the various queues and send the initialization command
* to the adapter.
*
* Results:
* Standard Sprite return status.
*
* Side effects:
* The adapter board is initialized.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraInitAdapter(statePtr)
NetUltraState *statePtr; /* State of the adapter. */
{
ReturnStatus status;
NetUltraInitCommand cmd; /* Init command block. */
Net_Interface *interPtr;
interPtr = statePtr->interPtr;
MASTER_LOCK(&interPtr->mutex);
if (!(statePtr->flags & NET_ULTRA_STATE_GO)) {
if (netUltraDebug) {
printf("NetUltraInitAdapter: device is not started.\n");
}
status = FAILURE;
goto exit;
}
bzero((char *) &cmd, sizeof(cmd));
cmd.opcode = NET_ULTRA_INIT_OPCODE;
cmd.toAdapterAddr = (int) DVMA_TO_VME(statePtr->firstToAdapterPtr,
statePtr);
cmd.toAdapterNum = statePtr->lastToAdapterPtr -
statePtr->firstToAdapterPtr + 1;
cmd.toHostAddr = (int) DVMA_TO_VME(statePtr->firstToHostPtr, statePtr);
cmd.toHostNum = statePtr->lastToHostPtr - statePtr->firstToHostPtr + 1;
cmd.XRBSize = sizeof(NetUltraXRB);
cmd.priority = (char) statePtr->priority;
cmd.vector = (char) interPtr->vector;
cmd.requestLevel = (char) statePtr->requestLevel;
cmd.addressSpace = (char) statePtr->addressSpace;
status = NetUltraSendCmd(statePtr, NET_ULTRA_INIT_OK, sizeof(cmd),
(Address) &cmd);
if (status != SUCCESS) {
if (cmd.reply == NET_ULTRA_BAD_SIZE) {
printf("NetUltraInitAdapter: adapter disagrees on size of XRB\n");
}
goto exit;
}
statePtr->flags &= ~NET_ULTRA_STATE_GO;
statePtr->flags |= NET_ULTRA_STATE_INIT;
exit:
MASTER_UNLOCK(&interPtr->mutex);
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraStart--
*
* Send a start request to the board.
* Assumes the interface mutex is held.
*
* Results:
* Standard Sprite return status.
*
* Side effects:
* A start request is sent to the board.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraStart(statePtr)
NetUltraState *statePtr; /* State of the adapter. */
{
NetUltraRequest request;
NetUltraStartRequest *startPtr;
NetUltraRequestHdr *hdrPtr;
Net_Interface *interPtr;
int i;
int power = 0;
int tmp;
ReturnStatus status = SUCCESS;
static int sequence = 0;
Sync_Condition startComplete;
interPtr = statePtr->interPtr;
startPtr = &request.start;
hdrPtr = &startPtr->hdr;
if (Net_AddrCmp(&interPtr->netAddress[NET_PROTO_RAW],
&netZeroAddress)){
printf(
"NetUltraStart: can't send start command - adapter address not set\n");
status = FAILURE;
goto exit;
}
if (statePtr->flags & NET_ULTRA_STATE_START) {
printf("NetUltraStart: adapter already started.\n");
status = FAILURE;
goto exit;
}
if (!(statePtr->flags & NET_ULTRA_STATE_INIT)) {
printf("NetUltraStart: adapter not initialized.\n");
status = FAILURE;
goto exit;
}
bzero((char *) &request, sizeof(request));
hdrPtr->cmd = NET_ULTRA_NEW_START_REQ;
startPtr->sequence = sequence;
sequence++;
startPtr->hostType = NET_ULTRA_START_HOSTTYPE_SUN;
/*
* Determine which power of 2 equals the maximum packet size.
*/
tmp = interPtr->maxBytes;
for (i = 0; i < sizeof(int) * 8; i++) {
if (tmp & 1) {
power = i;
}
tmp >>= 1;
}
if (1 << power > interPtr->maxBytes) {
power++;
}
startPtr->hostMaxBytes = power;
/*
* This part is kind of goofy. The adapter expects the network
* address to be 7 bytes long (the first byte is missing). We have
* to bcopy the netAddress minus its first byte.
*/
startPtr->netAddressSize = 7;
bcopy(&(((char *) &interPtr->netAddress[NET_PROTO_RAW])[1]),
(char *) &startPtr->netAddressBuf, sizeof(Net_UltraAddress)-1);
startPtr->netAddressBuf[0] = 0x49;
startPtr->netAddressBuf[5] = 0xfe;
status = NetUltraSendReq(statePtr, StandardDone,
(ClientData) &startComplete, FALSE,
0, (Net_ScatterGather *) NIL, sizeof(NetUltraStartRequest),
&request);
if (status != SUCCESS) {
printf("NetUltraStart: unable to send start request\n");
goto exit;
}
Sync_MasterWait(&(startComplete), &(interPtr->mutex), FALSE);
if (hdrPtr->status & NET_ULTRA_STATUS_OK) {
if (netUltraDebug) {
printf("NetUltraStart: hdrPtr->status = %d : %s\n",
hdrPtr->status, GetStatusString(hdrPtr->status));
}
if (netUltraDebug) {
printf("Ultranet adapter started\n");
printf("Ucode %d\n", startPtr->ucodeRel);
printf("Adapter type %d, adapter hw %d\n", startPtr->adapterType,
startPtr->adapterHW);
printf("Max VC = %d\n", startPtr->maxVC);
printf("Max DRCV = %d\n", startPtr->maxDRCV);
printf("Max DSND = %d\n", startPtr->maxDSND);
printf("Slot = %d\n", startPtr->slot);
printf("Speed = %d\n", startPtr->speed);
printf("Max bytes = %d\n", startPtr->adapterMaxBytes);
}
if (startPtr->maxDRCV < statePtr->maxReadPending) {
printf("NetUltraStart: WARNING: max pending reads reset to %d\n",
startPtr->maxDRCV);
statePtr->maxReadPending = startPtr->maxDRCV;
}
if (startPtr->maxDSND < statePtr->maxWritePending) {
printf("NetUltraStart: WARNING: max pending writes reset to %d\n",
startPtr->maxDSND);
statePtr->maxWritePending = startPtr->maxDSND;
}
if (startPtr->adapterMaxBytes < power) {
interPtr->maxBytes = 1 << power;
printf("NetUltraStart: WARNING: max bytes reset to %d\n",
interPtr->maxBytes);
}
statePtr->flags = (NET_ULTRA_STATE_EXIST | NET_ULTRA_STATE_START |
NET_ULTRA_STATE_NORMAL);
/*
* Now queue up pending reads.
*/
for (i = 0; i < statePtr->maxReadPending; i++) {
List_Links *itemPtr;
Address buffer;
itemPtr = List_First(statePtr->freeBufferList);
if (itemPtr == statePtr->freeBufferList) {
panic("NetUltraOutput: list screwup\n");
}
List_Remove(itemPtr);
buffer = BUFFER_TO_DVMA(itemPtr, statePtr);
status = NetUltraPendingRead(interPtr, statePtr->bufferSize,
buffer);
if (status != SUCCESS) {
printf("NetUltraStart: could not queue pending read.\n");
}
}
} else {
printf("NetUltraStart: start command failed <0x%x> : %s\n",
hdrPtr->status, GetStatusString(hdrPtr->status));
}
exit:
return status;
}
/*
*----------------------------------------------------------------------
*
* StandardDone --
*
* This is a callback routine that is called from the interrupt
* handler when "standard" commands complete. It copies the request
* from the XRB in the queue to the request structure pointed
* to by the XRB. This allows the XRB to be used again.
* If the data field in the info structure is not NIL then it
* is assumed to be a pointer to a condition variable and a
* broadcast is done on that variable.
*
*
* Results:
* None.
*
* Side effects:
* None.
*
*
*----------------------------------------------------------------------
*/
/* ARGSUSED */
static void
StandardDone(interPtr, infoPtr)
Net_Interface *interPtr; /* Interface. */
NetUltraXRBInfo *infoPtr; /* Info about XRB that completed. */
{
bcopy((char *) &infoPtr->xrbPtr->request, (char *) infoPtr->requestPtr,
infoPtr->requestSize);
if (infoPtr->doneData != (ClientData) NIL) {
Sync_Broadcast((Sync_Condition *) infoPtr->doneData);
}
}
/*
*----------------------------------------------------------------------
*
* NetUltraStop--
*
* Send a stop request to the board.
* Assumes the interface mutex is held.
*
* Results:
* Standard Sprite return status.
*
* Side effects:
* The adapter abandons what it is doing.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraStop(statePtr)
NetUltraState *statePtr; /* State of the adapter. */
{
NetUltraRequest request;
NetUltraStopRequest *stopPtr;
NetUltraRequestHdr *hdrPtr;
Net_Interface *interPtr;
ReturnStatus status = SUCCESS;
Sync_Condition stopComplete;
interPtr = statePtr->interPtr;
stopPtr = &request.stop;
hdrPtr = &stopPtr->hdr;
if (!(statePtr->flags & NET_ULTRA_STATE_START)) {
printf("NetUltraStop: adapter not started.\n");
status = FAILURE;
goto exit;
}
bzero((char *) &request, sizeof(request));
hdrPtr->cmd = NET_ULTRA_STOP_REQ;
status = NetUltraSendReq(statePtr, StandardDone,
(ClientData) &stopComplete, FALSE,
0, (Net_ScatterGather *) NIL, sizeof(NetUltraStopRequest),
&request);
if (status != SUCCESS) {
printf("NetUltraStop: unable to send stop request\n");
goto exit;
}
Sync_MasterWait(&(stopComplete), &(interPtr->mutex), FALSE);
if (hdrPtr->status & NET_ULTRA_STATUS_OK) {
if (netUltraDebug) {
printf("NetUltraStop: hdrPtr->status = %d : %s\n",
hdrPtr->status, GetStatusString(hdrPtr->status));
}
statePtr->flags &= ~NET_ULTRA_STATE_START;
} else {
printf("NetUltraStop: stop command failed <0x%x> : %s\n",
hdrPtr->status, GetStatusString(hdrPtr->status));
}
exit:
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraReset --
*
* Resets the board by sending it a stop command followed by a
* start command. The XRB queues are also initialized.
* Assumes the interface mutex is held.
*
* Results:
* A standard Sprite return status.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraReset(interPtr)
Net_Interface *interPtr; /* Interface to reset. */
{
ReturnStatus status = SUCCESS;
NetUltraState *statePtr; /* State of the adapter. */
statePtr = (NetUltraState *) interPtr->interfaceData;
status = NetUltraStop(statePtr);
if (status != NULL) {
printf("NetUltraReset: stop failed\n");
return status;
}
InitQueues(statePtr);
status = NetUltraStart(statePtr);
if (status != NULL) {
printf("NetUltraReset: start failed\n");
return status;
}
return status;
}
/*
*----------------------------------------------------------------------
*
* Net_UltraReset --
*
* This is a version of the reset routine that can be called
* from outside the module since it locks the mutex.
*
* Results:
*
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
void
Net_UltraReset(interPtr)
Net_Interface *interPtr; /* Interface to reset. */
{
MASTER_LOCK(&interPtr->mutex);
/*
* If we are at interrupt level we have to do a callback to reset
* the adapter since we can't wait for the response from
* the adapter (there may not be a current process and we can't
* get the interrupt).
*/
if (Mach_AtInterruptLevel()) {
Proc_CallFunc(NetUltraResetCallback, (ClientData) interPtr, 0);
} else {
(void) NetUltraReset(interPtr);
}
MASTER_UNLOCK(&interPtr->mutex);
}
/*
*----------------------------------------------------------------------
*
* NetUltraResetCallback --
*
* This routine is called by the Proc_ServerProc during the
* callback to reset the adapter.
*
* Results:
* None.
*
* Side effects:
* The adapter is reset.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static void
NetUltraResetCallback(data, infoPtr)
ClientData data; /* Ptr to the interface to reset. */
Proc_CallInfo *infoPtr; /* Unused. */
{
Net_UltraReset((Net_Interface *) data);
}
/*
*----------------------------------------------------------------------
*
* Net_UltraHardReset --
*
* This is a version of the hard reset routine that can be called from
* outside the net module because it does not assume that a
* lock is held (or interrupts are disabled) when it is called.
*
* Results:
* None.
*
* Side effects:
* The adapter is reset.
*
*----------------------------------------------------------------------
*/
void
Net_UltraHardReset(interPtr)
Net_Interface *interPtr; /* Interface to reset. */
{
MASTER_LOCK(&interPtr->mutex);
NetUltraHardReset(interPtr);
MASTER_UNLOCK(&interPtr->mutex);
}
/*
*----------------------------------------------------------------------
*
* NetUltraDiag --
*
* Send a diagnostic command to the adapter.
*
* Results:
* SUCCESS if the adapter processed the command correctly,
* FAILURE otherwise.
*
* Side effects:
* The adapter is sent a diagnostic command.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraDiag(statePtr, cmdPtr)
NetUltraState *statePtr; /* State of the adapter. */
NetUltraDiagCommand *cmdPtr; /* Diagnostic command block. */
{
ReturnStatus status = SUCCESS;
NetUltraDiagCommand tmpCmd;
int inSize;
int outSize;
int fmtStatus;
MASTER_LOCK(&statePtr->interPtr->mutex);
if (!(statePtr->flags & NET_ULTRA_STATE_EPROM)) {
if (netUltraDebug) {
printf("NetUltraDiag: device is not in EPROM state.\n");
}
status = FAILURE;
goto exit;
}
if (netUltraDebug) {
printf("Sending diagnostic command to adapter.\n");
}
bzero((char *) &tmpCmd, sizeof(tmpCmd));
tmpCmd.opcode = NET_ULTRA_DIAG_OPCODE;
status = NetUltraSendCmd(statePtr, NET_ULTRA_DIAG_OK,
sizeof(tmpCmd), (Address) &tmpCmd);
if (status != SUCCESS) {
goto exit;
}
cmdPtr->reply = tmpCmd.reply;
cmdPtr->version = tmpCmd.version;
cmdPtr->error = tmpCmd.error;
/*
* The hardware related fields are returned in Intel 386 byte-order.
*/
inSize = 5 * sizeof(int);
outSize = inSize;
fmtStatus = Fmt_Convert("w5", NET_ULTRA_FORMAT, &inSize,
(char *) &(tmpCmd.hwModel), mach_Format, &outSize,
(char *) &(cmdPtr->hwModel));
if (fmtStatus != 0) {
printf("NetUltraInfo: Format returned %d\n");
status = FAILURE;
goto exit;
}
exit:
MASTER_UNLOCK(&statePtr->interPtr->mutex)
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraInfo --
*
* Send an info command to the adapter. The results are the same
* as the diagnostic command, except the diagnostics are not
* actually run. Presumably we are fetching the results of the
* last time diagnostics were run, probably due to a reset.
*
* Results:
* SUCCESS if the adapter processed the command correctly,
* FAILURE otherwise.
*
* Side effects:
* The adapter is sent an info command.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraInfo(statePtr, cmdPtr)
NetUltraState *statePtr; /* State of the adapter. */
NetUltraInfoCommand *cmdPtr; /* Info command block. */
{
ReturnStatus status = SUCCESS;
int fmtStatus;
NetUltraInfoCommand tmpCmd;
int inSize;
int outSize;
MASTER_LOCK(&statePtr->interPtr->mutex);
if (!(statePtr->flags & NET_ULTRA_STATE_EPROM)) {
if (netUltraDebug) {
printf("NetUltraInfo: device is not in EPROM state.\n");
}
status = FAILURE;
goto exit;
}
if (netUltraDebug) {
printf("Sending Info command to adapter.\n");
}
bzero((char *) &tmpCmd, sizeof(NetUltraInfoCommand));
tmpCmd.opcode = NET_ULTRA_INFO_OPCODE;
status = NetUltraSendCmd(statePtr, NET_ULTRA_INFO_OK,
sizeof(NetUltraInfoCommand), (Address) &tmpCmd);
if (status != SUCCESS) {
goto exit;
}
cmdPtr->reply = tmpCmd.reply;
cmdPtr->version = tmpCmd.version;
cmdPtr->error = tmpCmd.error;
/*
* The hardware related fields are returned in Intel 386 byte-order.
*/
inSize = 5 * sizeof(int);
outSize = inSize;
fmtStatus = Fmt_Convert("w5", NET_ULTRA_FORMAT, &inSize,
(char *) &(tmpCmd.hwModel), mach_Format, &outSize,
(char *) &(cmdPtr->hwModel));
if (fmtStatus != 0) {
printf("NetUltraInfo: Format returned %d\n");
status = FAILURE;
}
exit:
MASTER_UNLOCK(&statePtr->interPtr->mutex)
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraExtDiag --
*
* Send an extended diagnostic command to the adapter.
*
* Results:
* SUCCESS if the adapter processed the command correctly,
* FAILURE otherwise.
*
* Side effects:
* The adapter is sent an extended diagnostic command.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraExtDiag(statePtr, external, buffer, cmdPtr)
NetUltraState *statePtr; /* State of the adapter. */
Boolean external; /* TRUE => use external loopback
* adapter. */
char buffer[]; /* Used for VME tests. */
NetUltraExtDiagCommand *cmdPtr; /* Extended diagnostic command
* block. */
{
ReturnStatus status = SUCCESS;
Address bufAddress;
MASTER_LOCK(&statePtr->interPtr->mutex);
if (!(statePtr->flags & NET_ULTRA_STATE_EPROM)) {
if (netUltraDebug) {
printf("NetUltraExtDiag: device is not in EPROM state.\n");
}
status = FAILURE;
goto exit;
}
if (netUltraDebug) {
printf("Sending extended diagnostic command to adapter.\n");
}
bufAddress = (Address) VmMach_DMAAlloc(NET_ULTRA_EXT_DIAG_BUF_SIZE, buffer);
if (bufAddress == (Address) NIL) {
printf("NetUltraExtDiag: unable to allocate buffer in DMA space.\n");
status = FAILURE;
}
bzero((char *) cmdPtr, sizeof(*cmdPtr));
cmdPtr->opcode = NET_ULTRA_EXT_DIAG_OPCODE;
cmdPtr->externalLoopback = (external == TRUE) ? 1 : 0;
cmdPtr->bufferAddress = (int) DVMA_TO_VME(bufAddress, statePtr);
status = NetUltraSendCmd(statePtr, NET_ULTRA_EXT_DIAG_OK, sizeof(*cmdPtr),
(Address) cmdPtr);
VmMach_DMAFree(NET_ULTRA_EXT_DIAG_BUF_SIZE, bufAddress);
exit:
MASTER_UNLOCK(&statePtr->interPtr->mutex);
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraLoad --
*
* Download a block of ucode onto the adapter.
*
* Results:
* SUCCESS if the command was processed properly
*
* Side effects:
* Data is loaded into the adapter ram.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraLoad(statePtr, address, length, ucodePtr)
NetUltraState *statePtr; /* State of the adapter. */
int address; /* Load address of ucode. */
int length; /* Size of ucode. */
Address ucodePtr; /* Ucode buffer. */
{
NetUltraLoadCommand cmd;
int inSize;
int outSize;
int fmtStatus;
Address dmaAddress;
ReturnStatus status = SUCCESS;
MASTER_LOCK(&statePtr->interPtr->mutex);
if (!(statePtr->flags & NET_ULTRA_STATE_EPROM)) {
if (netUltraDebug) {
printf("NetUltraExtDiag: device is not in EPROM state.\n");
}
status = FAILURE;
goto exit;
}
if (netUltraDebug) {
printf("Sending load command to adapter.\n");
printf("Address = 0x%x, length = %d\n", address, length);
}
/*
* Convert the address and length to Intel format.
*/
inSize = sizeof(int);
outSize = sizeof(int);
fmtStatus = Fmt_Convert("w", mach_Format, &inSize,
(char *) &address, NET_ULTRA_FORMAT, &outSize,
(char *) &(cmd.loadAddress));
if (fmtStatus != 0) {
printf("NetUltraLoad: Fmt_Convert returned %d\n",
fmtStatus);
status = FAILURE;
goto exit;
}
inSize = sizeof(int);
outSize = sizeof(int);
fmtStatus = Fmt_Convert("w", mach_Format, &inSize,
(char *) &length, NET_ULTRA_FORMAT, &outSize,
(char *) &(cmd.length));
if (fmtStatus != 0) {
printf("NetUltraLoad: Fmt_Convert returned %d\n",
fmtStatus);
status = FAILURE;
goto exit;
}
cmd.opcode = NET_ULTRA_LOAD_OPCODE;
cmd.reply = 0;
/*
* Map the ucode into DVMA space.
*/
dmaAddress = (Address) VmMach_DMAAlloc(length, ucodePtr);
cmd.dataAddress = (unsigned long) DVMA_TO_VME(dmaAddress, statePtr);
status = NetUltraSendCmd(statePtr, NET_ULTRA_LOAD_OK, sizeof(cmd),
(Address) &cmd);
VmMach_DMAFree(length, dmaAddress);
if (status != SUCCESS) {
goto exit;
}
statePtr->flags |= NET_ULTRA_STATE_LOAD;
exit:
MASTER_UNLOCK(&statePtr->interPtr->mutex)
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraGo --
*
* Send the go command to the adapter to start its processor
* running the ucode.
*
* Results:
* SUCCESS if it worked, FAILURE otherwise
*
* Side effects:
* The adapter cpu begins executing.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraGo(statePtr, address)
NetUltraState *statePtr; /* State of the adapter. */
int address; /* Start address. */
{
NetUltraGoCommand cmd;
int inSize;
int outSize;
int fmtStatus;
ReturnStatus status = SUCCESS;
MASTER_LOCK(&statePtr->interPtr->mutex);
if (!(statePtr->flags & NET_ULTRA_STATE_EPROM)) {
if (netUltraDebug) {
printf("NetUltraExtDiag: device is not in EPROM state.\n");
}
status = FAILURE;
goto exit;
}
if (!(statePtr->flags & NET_ULTRA_STATE_LOAD)) {
if (netUltraDebug) {
printf("NetUltraGo: ucode not downloaded.\n");
}
status = FAILURE;
goto exit;
}
if (netUltraDebug) {
printf("Sending go command to adapter.\n");
}
/*
* Convert the address into Intel format.
*/
inSize = sizeof(int);
outSize = sizeof(int);
fmtStatus = Fmt_Convert("w", mach_Format, &inSize,
(char *) &address, NET_ULTRA_FORMAT, &outSize,
(char *) &(cmd.startAddress));
if (fmtStatus != 0) {
printf("NetUltraGo: Fmt_Convert returned %d\n",
fmtStatus);
status = FAILURE;
goto exit;
}
cmd.opcode = NET_ULTRA_GO_OPCODE;
cmd.reply = 0;
status = NetUltraSendCmd(statePtr, NET_ULTRA_GO_OK, sizeof(cmd),
(Address) &cmd);
if (status != SUCCESS) {
goto exit;
}
statePtr->flags &= ~NET_ULTRA_STATE_LOAD;
statePtr->flags |= NET_ULTRA_STATE_GO;
statePtr->flags &= ~NET_ULTRA_STATE_EPROM;
exit:
MASTER_UNLOCK(&statePtr->interPtr->mutex)
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraSendCmd --
*
* Send a command to the adapter.
*
* Results:
* SUCCESS if the adapter responded to the command,
* DEV_TIMEOUT if the adapter did not respond
*
* Side effects:
* A command is sent to the adapter.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraSendCmd(statePtr, ok,size, cmdPtr)
NetUltraState *statePtr; /* State of the adapter. */
int ok; /* Value of reply field if command
* was successful. */
int size; /* Size of command block. */
Address cmdPtr; /* The command block. */
{
struct StdCmd {
volatile int opcode;
volatile int reply;
} *stdCmdPtr;
ReturnStatus status = SUCCESS;
stdCmdPtr = (struct StdCmd *) cmdPtr;
if (netUltraDebug) {
printf("NetUltraSendCmd: sending command %d to adapter\n",
stdCmdPtr->opcode);
printf("NetUltraSendCmd: cmdPtr = 0x%x\n", cmdPtr);
}
if ((int) cmdPtr & 0x3) {
panic("NetUltraSendCmd: command not aligned on a word boundary\n");
}
stdCmdPtr->reply = 0;
cmdPtr = VmMach_DMAAlloc(size, cmdPtr);
if (cmdPtr == (Address) NIL) {
panic("NetUltraSendCmd: can't allocate DMA space for command\n");
}
if (netUltraDebug) {
printf("NetUltraSendCmd: cmdPtr mapped into DMA space\n");
printf("NetUltraSendCmd: cmdPtr = 0x%x\n", cmdPtr);
}
*statePtr->intrReg =
(int) DVMA_TO_VME(cmdPtr,statePtr);
WAIT_FOR_REPLY(&stdCmdPtr->reply, NET_ULTRA_DELAY);
VmMach_DMAFree(size, cmdPtr);
if (stdCmdPtr->reply == 0) {
printf("NetUltraSendCmd: adapter timed out\n");
status = DEV_TIMEOUT;
} else if (stdCmdPtr->reply == ok) {
status = SUCCESS;
} else {
printf("NetUltraSendCmd: adapter returned %d\n", stdCmdPtr->reply);
status = FAILURE;
}
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraIntr --
*
* Handle an interrupt from the Ultranet adapter.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
void
NetUltraIntr(interPtr, polling)
Net_Interface *interPtr; /* Interface to process. */
Boolean polling; /* TRUE if are being polled instead of
* processing an interrupt. */
{
NetUltraXRB *xrbPtr;
NetUltraXRB *nextXRBPtr;
NetUltraState *statePtr;
NetUltraDMAInfo *dmaPtr;
NetUltraRequestHdr *hdrPtr;
NetUltraXRBInfo *infoPtr;
int processed;
NetUltraTraceInfo *tracePtr;
Address buffer;
MASTER_LOCK(&interPtr->mutex);
#ifndef CLEAN
if (netUltraDebug) {
printf("Received an Ultranet interrupt.\n");
}
#endif
statePtr = (NetUltraState *) interPtr->interfaceData;
xrbPtr = statePtr->nextToHostPtr;
#ifndef CLEAN
if (netUltraTrace) {
NEXT_TRACE(statePtr, &tracePtr);
tracePtr->event = INTERRUPT;
Timer_GetCurrentTicks(&tracePtr->ticks);
}
#endif
processed = 0;
while(xrbPtr->filled != 0) {
/*
* Compute the next xrb to the host.
*/
if (xrbPtr == statePtr->lastToHostPtr) {
nextXRBPtr = statePtr->firstToHostPtr;
} else {
nextXRBPtr = xrbPtr + 1;
}
statePtr->nextToHostPtr = nextXRBPtr;
dmaPtr = &xrbPtr->dma;
if (!(dmaPtr->cmd & NET_ULTRA_DMA_CMD_FROM_ADAPTER)) {
printf("NetUltraIntr: cmd (0x%x) not from adapter?\n", dmaPtr->cmd);
goto endLoop;
}
if ((dmaPtr->cmd & NET_ULTRA_DMA_CMD_MASK) != NET_ULTRA_DMA_CMD_XRB) {
printf("NetUltraIntr: dmaPtr->cmd = 0x%x\n", dmaPtr->cmd);
goto endLoop;
}
hdrPtr = (NetUltraRequestHdr *) &xrbPtr->request;
infoPtr = hdrPtr->infoPtr;
if (infoPtr->flags & NET_ULTRA_INFO_PENDING) {
#ifndef CLEAN
if (netUltraDebug) {
printf("NetUltraIntr: processing 0x%x\n", infoPtr);
}
if (netUltraTrace) {
NEXT_TRACE(statePtr, &tracePtr);
tracePtr->event = PROCESS_XRB;
tracePtr->index = xrbPtr - statePtr->firstToHostPtr;
tracePtr->infoPtr = infoPtr;
Timer_GetCurrentTicks(&tracePtr->ticks);
}
#endif
infoPtr->xrbPtr = xrbPtr;
if (statePtr->flags & NET_ULTRA_STATE_STATS) {
if (hdrPtr->cmd == NET_ULTRA_DGRAM_RECV_REQ) {
statePtr->stats.packetsReceived++;
statePtr->stats.bytesReceived += hdrPtr->size;
statePtr->stats.receivedHistogram[hdrPtr->size >> 10]++;
}
}
/*
* Mark the info as not pending.
* Clearing the pending bit ensures
* that this packet does not get processed twice, since the
* master lock around the interface will get released before
* calling the RPC system, so that the RPC system can
* output a packet. Do not
* clear the filled bit since we are using the contents of
* the xrb and we don't want the adapter to overwrite it
* yet.
*/
infoPtr->flags &= ~NET_ULTRA_INFO_PENDING;
if (infoPtr->doneProc != NILPROC) {
(infoPtr->doneProc)(interPtr, infoPtr);
}
if (infoPtr->flags & NET_ULTRA_INFO_STD_BUFFER) {
if (infoPtr->flags & NET_ULTRA_INFO_REMAP) {
VmMach_DMAFree(hdrPtr->size,
VME_TO_DVMA(hdrPtr->buffer, statePtr));
buffer = infoPtr->buffer;
} else {
buffer = VME_TO_BUFFER(hdrPtr->buffer, statePtr);
}
List_InitElement((List_Links *) buffer);
List_Insert((List_Links *) buffer,
LIST_ATREAR(statePtr->freeBufferList));
}
List_Remove((List_Links *) infoPtr);
List_Insert((List_Links *) infoPtr,
LIST_ATREAR(statePtr->freeXRBInfoList));
processed++;
} else {
#ifndef CLEAN
if (netUltraTrace) {
NEXT_TRACE(statePtr, &tracePtr);
tracePtr->event = INFO_NOT_PENDING;
tracePtr->index = xrbPtr - statePtr->firstToHostPtr;
tracePtr->infoPtr = infoPtr;
}
#endif
}
endLoop:
xrbPtr->filled = 0;
xrbPtr = nextXRBPtr;
/*
* Check and see if there is a free xrb in the "to adapter"
* queue. Presumably the appearance of one in the "to host"
* queue implies one freed up in the "to adapter" queue.
*/
if ((statePtr->nextToAdapterPtr->filled != 0) &&
(statePtr->toAdapterAvail.waiting == TRUE)) {
Sync_Broadcast(&statePtr->toAdapterAvail);
}
}
#ifndef CLEAN
if (processed == 0) {
if (netUltraDebug) {
printf("NetUltraIntr: didn't process any packets.\n");
}
}
#endif
MASTER_UNLOCK(&interPtr->mutex);
}
/*
*----------------------------------------------------------------------
*
* NetUltraIOControl --
*
* Handle ioctls for the Ultranet adapter..
*
* Results:
* SUCCESS if the ioctl was performed successfully, a standard
* Sprite error code otherwise.
*
* Side effects:
* Commands may be sent to the adapter and the adapter state
* may change.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
ReturnStatus
NetUltraIOControl(interPtr, ioctlPtr, replyPtr)
Net_Interface *interPtr; /* Interface on which to perform ioctl. */
Fs_IOCParam *ioctlPtr; /* Standard I/O Control parameter block */
Fs_IOReply *replyPtr; /* Size of outBuffer and returned signal */
{
ReturnStatus status = SUCCESS;
int fmtStatus;
int inSize;
int outSize;
NetUltraState *statePtr = (NetUltraState *) interPtr->interfaceData;
if (netUltraDebug) {
printf("NetUltraIOControl: command = %d\n", ioctlPtr->command);
}
if ((ioctlPtr->command & ~0xffff) != IOC_ULTRA) {
return DEV_INVALID_ARG;
}
switch(ioctlPtr->command) {
case IOC_ULTRA_SET_FLAGS:
case IOC_ULTRA_RESET_FLAGS:
case IOC_ULTRA_GET_FLAGS:
return GEN_NOT_IMPLEMENTED;
break;
case IOC_ULTRA_CLR:
case IOC_ULTRA_INT:
case IOC_ULTRA_WFI:
return DEV_INVALID_ARG;
break;
case IOC_ULTRA_DUMP:
return GEN_NOT_IMPLEMENTED;
break;
case IOC_ULTRA_DEBUG: {
int value;
outSize = sizeof(int);
inSize = ioctlPtr->inBufSize;
fmtStatus = Fmt_Convert("w", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &value);
if (fmtStatus != 0) {
printf("Format of IOC_ULTRA_DEBUG parameter failed, 0x%x\n",
fmtStatus);
return GEN_INVALID_ARG;
}
netUltraDebug = value;
break;
}
case IOC_ULTRA_TRACE: {
int value;
outSize = sizeof(int);
inSize = ioctlPtr->inBufSize;
fmtStatus = Fmt_Convert("w", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &value);
if (fmtStatus != 0) {
printf("Format of IOC_ULTRA_TRACE parameter failed, 0x%x\n",
fmtStatus);
return GEN_INVALID_ARG;
}
netUltraTrace = value;
break;
}
case IOC_ULTRA_RESET:
Net_UltraReset(interPtr);
break;
case IOC_ULTRA_HARD_RESET:
Net_UltraHardReset(interPtr);
break;
case IOC_ULTRA_GET_ADAP_INFO: {
NetUltraInfoCommand cmd;
Dev_UltraAdapterInfo info;
status = NetUltraInfo(statePtr, &cmd);
if (status != SUCCESS) {
return status;
}
info.version = cmd.version;
info.error = cmd.error;
info.hwModel = cmd.hwModel;
info.hwVersion = cmd.hwVersion;
info.hwRevision = cmd.hwRevision;
info.hwOption = cmd.hwOption;
info.hwSerial = cmd.hwSerial;
inSize = sizeof(info);
outSize = ioctlPtr->outBufSize;
fmtStatus = Fmt_Convert("{w7}", mach_Format, &inSize,
(Address) &info, ioctlPtr->format, &outSize,
(Address) ioctlPtr->outBuffer);
if (fmtStatus != 0) {
if (fmtStatus == FMT_OUTPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf(
"NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
break;
}
case IOC_ULTRA_DIAG: {
NetUltraDiagCommand cmd;
Dev_UltraDiag diag;
status = NetUltraDiag(statePtr, &cmd);
if (status != SUCCESS) {
return status;
}
diag.version = cmd.version;
diag.error = cmd.error;
diag.hwModel = cmd.hwModel;
diag.hwVersion = cmd.hwVersion;
diag.hwRevision = cmd.hwRevision;
diag.hwOption = cmd.hwOption;
diag.hwSerial = cmd.hwSerial;
inSize = sizeof(diag);
outSize = ioctlPtr->outBufSize;
fmtStatus = Fmt_Convert("{w7}", mach_Format, &inSize,
(Address) &diag, ioctlPtr->format, &outSize,
(Address) ioctlPtr->outBuffer);
if (fmtStatus != 0) {
if (fmtStatus == FMT_OUTPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf(
"NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
break;
}
case IOC_ULTRA_EXTENDED_DIAG: {
NetUltraExtDiagCommand cmd;
Dev_UltraExtendedDiag extDiag;
char *buffer;
buffer = (char *) malloc(NET_ULTRA_EXT_DIAG_BUF_SIZE);
inSize = ioctlPtr->inBufSize;
outSize = sizeof(extDiag);
fmtStatus = Fmt_Convert("{w3}", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &extDiag);
if (fmtStatus != 0) {
if (fmtStatus == FMT_INPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf("NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
status = NetUltraExtDiag(statePtr, extDiag.externalLoopback,
buffer,&cmd);
free(buffer);
if (status != SUCCESS) {
return status;
}
extDiag.version = cmd.version;
extDiag.error = cmd.error;
inSize = sizeof(extDiag);
outSize = ioctlPtr->outBufSize;
fmtStatus = Fmt_Convert("{w3}", mach_Format, &inSize,
(Address) &extDiag, ioctlPtr->format, &outSize,
(Address) ioctlPtr->outBuffer);
if (fmtStatus != 0) {
if (fmtStatus == FMT_OUTPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf(
"NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
break;
}
case IOC_ULTRA_LOAD: {
Dev_UltraLoad load;
Address ucodePtr;
inSize = 2 * sizeof(int);
outSize = sizeof(load);
fmtStatus = Fmt_Convert("w2", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &load);
if (fmtStatus != 0) {
if (fmtStatus == FMT_INPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf("NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
/*
* This assumes that there isn't any padding between the
* two integers in NetUltraLoadCommand and the data buffer.
*/
ucodePtr = (Address) ioctlPtr->inBuffer + inSize;
status = NetUltraLoad(statePtr, load.address, load.length,
ucodePtr);
break;
}
case IOC_ULTRA_GO: {
Dev_UltraGo go;
inSize = ioctlPtr->inBufSize;
outSize = sizeof(go);
fmtStatus = Fmt_Convert("{w1}", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &go.address);
if (fmtStatus != 0) {
if (fmtStatus == FMT_INPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf("NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
status = NetUltraGo(statePtr, go.address);
break;
}
case IOC_ULTRA_INIT: {
status = NetUltraInitAdapter(statePtr);
break;
}
case IOC_ULTRA_START: {
MASTER_LOCK(&interPtr->mutex);
status = NetUltraStart(statePtr);
MASTER_UNLOCK(&interPtr->mutex);
break;
}
case IOC_ULTRA_ADDRESS: {
/*
* Set the adapter address. This is not the normal way to
* do this (usually happens during route installation) but
* it is useful for debugging.
*/
Net_UltraAddress address;
int group;
int unit;
inSize = ioctlPtr->inBufSize;
outSize = sizeof(Net_UltraAddress);
fmtStatus = Fmt_Convert("{b8}", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &address);
if (fmtStatus != 0) {
if (fmtStatus == FMT_INPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf("NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
Net_UltraAddressGet(&address, &group, &unit);
printf("Setting ultra address to %d/%d\n", group, unit);
MASTER_LOCK(&interPtr->mutex);
status = Net_SetAddress(NET_ADDRESS_ULTRA,
(Address) &address,
&interPtr->netAddress[NET_PROTO_RAW]);
if (status != SUCCESS) {
panic("NetUltraIOControl: Net_SetAddress failed\n");
}
MASTER_UNLOCK(&interPtr->mutex);
break;
}
case IOC_ULTRA_SEND_DGRAM: {
Dev_UltraSendDgram dgram;
inSize = ioctlPtr->inBufSize;
outSize = sizeof(dgram);
fmtStatus = Fmt_Convert("{w2{w2}wb*}", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &dgram);
if (fmtStatus != 0) {
if (fmtStatus == FMT_INPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf("NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
status = NetUltraSendDgram(interPtr, &dgram.address, dgram.count,
dgram.size,
(dgram.useBuffer == TRUE) ? (Address) dgram.buffer :
(Address) NIL, &dgram.time);
inSize = sizeof(dgram);
outSize = ioctlPtr->outBufSize;
fmtStatus = Fmt_Convert("{w2{w2}wb*}", mach_Format, &inSize,
(Address) &dgram, ioctlPtr->format, &outSize,
(Address) ioctlPtr->outBuffer);
if (fmtStatus != 0) {
if (fmtStatus == FMT_OUTPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf(
"NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
break;
}
case IOC_ULTRA_ECHO: {
Dev_UltraEcho echo;
inSize = ioctlPtr->inBufSize;
outSize = sizeof(echo);
fmtStatus = Fmt_Convert("{w}", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &echo);
if (fmtStatus != 0) {
if (fmtStatus == FMT_INPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf("NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
if (echo.echo == TRUE) {
statePtr->flags |= NET_ULTRA_STATE_ECHO;
statePtr->flags &= ~NET_ULTRA_STATE_NORMAL;
} else {
statePtr->flags &= ~NET_ULTRA_STATE_ECHO;
statePtr->flags |= NET_ULTRA_STATE_NORMAL;
}
break;
}
case IOC_ULTRA_SOURCE: {
Dev_UltraSendDgram dgram;
inSize = ioctlPtr->inBufSize;
outSize = sizeof(dgram);
fmtStatus = Fmt_Convert("{w2{w2}wb*}", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &dgram);
if (fmtStatus != 0) {
if (fmtStatus == FMT_INPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf("NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
status = NetUltraSource(interPtr, &dgram.address, dgram.count,
dgram.size,
(dgram.useBuffer == TRUE) ? (Address) dgram.buffer :
(Address) NIL, &dgram.time);
inSize = sizeof(dgram);
outSize = ioctlPtr->outBufSize;
fmtStatus = Fmt_Convert("{w2{w2}wb*}", mach_Format, &inSize,
(Address) &dgram, ioctlPtr->format, &outSize,
(Address) ioctlPtr->outBuffer);
if (fmtStatus != 0) {
if (fmtStatus == FMT_OUTPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf(
"NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
break;
}
case IOC_ULTRA_SINK: {
Dev_UltraSink sink;
int value;
outSize = sizeof(int);
inSize = ioctlPtr->inBufSize;
fmtStatus = Fmt_Convert("w", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &value);
if (fmtStatus != 0) {
printf("Format of IOC_ULTRA_TRACE parameter failed, 0x%x\n",
fmtStatus);
return GEN_INVALID_ARG;
}
outSize = ioctlPtr->outBufSize;
sink.packets = packetsSunk;
Timer_SubtractTicks(sinkEndTime, sinkStartTime, &sink.time);
Timer_TicksToTime(sink.time, &sink.time);
inSize = sizeof(sink);
fmtStatus = Fmt_Convert("w{w2}", mach_Format, &inSize,
(Address) &sink, ioctlPtr->format, &outSize,
ioctlPtr->outBuffer);
if (fmtStatus != 0) {
printf("Format of IOC_ULTRA_TRACE parameter failed, 0x%x\n",
fmtStatus);
return GEN_INVALID_ARG;
}
if (value > 0) {
statePtr->flags |= NET_ULTRA_STATE_SINK;
statePtr->flags &= ~NET_ULTRA_STATE_NORMAL;
packetsSunk = 0;
} else {
statePtr->flags &= ~NET_ULTRA_STATE_SINK;
statePtr->flags |= NET_ULTRA_STATE_NORMAL;
}
break;
}
case IOC_ULTRA_COLLECT_STATS: {
int value;
inSize = ioctlPtr->inBufSize;
outSize = sizeof(int);
fmtStatus = Fmt_Convert("w", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &value);
if (fmtStatus != 0) {
if (fmtStatus == FMT_INPUT_TOO_SMALL) {
return GEN_INVALID_ARG;
} else {
printf("NetUltraIOControl: Fmt_Convert returned %d\n",
fmtStatus);
return FAILURE;
}
}
if (value == TRUE) {
statePtr->flags |= NET_ULTRA_STATE_STATS;
} else {
statePtr->flags &= ~NET_ULTRA_STATE_STATS;
}
break;
}
case IOC_ULTRA_CLEAR_STATS: {
bzero((char *) &statePtr->stats, sizeof(statePtr->stats));
break;
}
case IOC_ULTRA_GET_STATS: {
outSize = ioctlPtr->outBufSize;
inSize = sizeof(Dev_UltraStats);
fmtStatus = Fmt_Convert("w*", mach_Format, &inSize,
(Address) &statePtr->stats,
ioctlPtr->format, &outSize,
ioctlPtr->outBuffer);
if (fmtStatus != 0) {
printf("Format of IOC_ULTRA_GET_STATS parameter failed, 0x%x\n",
fmtStatus);
return GEN_INVALID_ARG;
}
break;
}
case IOC_ULTRA_MAP_THRESHOLD: {
int value;
outSize = sizeof(int);
inSize = ioctlPtr->inBufSize;
fmtStatus = Fmt_Convert("w", ioctlPtr->format, &inSize,
ioctlPtr->inBuffer, mach_Format, &outSize,
(Address) &value);
if (fmtStatus != 0) {
printf(
"Format of IOC_ULTRA_MAP_THRESHOLD parameter failed, 0x%x\n",
fmtStatus);
return GEN_INVALID_ARG;
}
netUltraMapThreshold = value;
break;
}
default: {
printf("NetUltraIOControl: unknown ioctl 0x%x\n",
ioctlPtr->command);
}
}
return status;
}
/*
*----------------------------------------------------------------------
*
* NetUltraSendReq --
*
* Queue up a request for the adapter board. If there isn't
* any room in the queue then we block until there is.
*
* Results:
* Standard Sprite return status.
*
* Side effects:
* The adapter board is notified of the addition to the queue.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraSendReq(statePtr, doneProc, data, rpc, scatterLength, scatterPtr,
requestSize, requestPtr)
NetUltraState *statePtr; /* State of the adapter. */
void (*doneProc)(); /* Procedure to call when
* XRB is done. */
ClientData data; /* Data used by doneProc. */
Boolean rpc; /* Is this an RPC packet? */
int scatterLength; /* Size of scatter/gather array. */
Net_ScatterGather *scatterPtr; /* The scatter/gather array. */
int requestSize; /* Size of the request. */
NetUltraRequest *requestPtr; /* Request to be sent. */
{
NetUltraXRB *xrbPtr;
NetUltraRequestHdr *hdrPtr;
NetUltraDMAInfo *dmaPtr;
ReturnStatus status = SUCCESS;
int signal;
NetUltraXRBInfo *infoPtr;
NetUltraTraceInfo *tracePtr;
int size;
int i;
if (netUltraDebug) {
printf("NetUltraSendReq: sending a request\n");
}
xrbPtr = statePtr->nextToAdapterPtr;
#ifndef CLEAN
if (netUltraTrace) {
NEXT_TRACE(statePtr, &tracePtr);
tracePtr->event = SEND_REQ;
tracePtr->index = xrbPtr - statePtr->firstToAdapterPtr;
Timer_GetCurrentTicks(&tracePtr->ticks);
}
#endif
if (statePtr->nextToAdapterPtr->filled) {
#ifndef CLEAN
if (netUltraTrace) {
NEXT_TRACE(statePtr, &tracePtr);
tracePtr->event = TO_ADAPTER_FILLED;
tracePtr->index = statePtr->nextToAdapterPtr -
statePtr->firstToAdapterPtr;
}
#endif
do {
if (netUltraDebug) {
printf("NetUltraSendReq: no XRB free, waiting\n");
}
statePtr->toAdapterAvail.waiting = TRUE;
signal = Sync_SlowMasterWait(
(unsigned int) &statePtr->toAdapterAvail,
&statePtr->interPtr->mutex, TRUE);
if (signal) {
return GEN_ABORTED_BY_SIGNAL;
}
} while(statePtr->nextToAdapterPtr->filled);
}
xrbPtr = statePtr->nextToAdapterPtr;
hdrPtr = (NetUltraRequestHdr *) requestPtr;
infoPtr = (NetUltraXRBInfo *) List_First(statePtr->freeXRBInfoList);
if ((List_Links *) infoPtr == statePtr->freeXRBInfoList) {
panic("NetUltraSendReq: no available XRBInfo structures!");
}
List_Remove((List_Links *) infoPtr);
List_Insert((List_Links *) infoPtr,
LIST_ATFRONT(statePtr->pendingXRBInfoList));
infoPtr->doneProc = doneProc;
infoPtr->doneData = data;
infoPtr->xrbPtr = xrbPtr;
infoPtr->scatterPtr = scatterPtr;
infoPtr->scatterLength = scatterLength;
infoPtr->requestSize = requestSize;
infoPtr->requestPtr = (union NetUltraRequest *) requestPtr;
infoPtr->flags = NET_ULTRA_INFO_PENDING;
#ifndef CLEAN
if (netUltraDebug) {
printf("NetUltraSendReq: using 0x%x\n", infoPtr);
}
#endif
#ifndef CLEAN
if (netUltraTrace) {
NEXT_TRACE(statePtr, &tracePtr);
tracePtr->event = SEND_REQ_INFO;
tracePtr->index = xrbPtr - statePtr->firstToAdapterPtr;
tracePtr->infoPtr = infoPtr;
}
#endif
hdrPtr->infoPtr = infoPtr;
hdrPtr->status = 0;
hdrPtr->reference = 0;
if (scatterLength > 0) {
Address buffer;
List_Links *itemPtr;
/*
* If the buffer is not in DVMA space then get one that is.
*/
if (! DVMA_ADDRESS(scatterPtr[0].bufAddr, statePtr)) {
if (netUltraDebug) {
printf("Data is not in DVMA space.\n");
}
while(List_IsEmpty(statePtr->freeBufferList)) {
int signal;
statePtr->bufferAvail.waiting = TRUE;
signal = Sync_SlowMasterWait(
(unsigned int) &statePtr->bufferAvail,
&statePtr->interPtr->mutex, TRUE);
if (signal) {
status = GEN_ABORTED_BY_SIGNAL;
goto exit;
}
}
itemPtr = List_First(statePtr->freeBufferList);
if (itemPtr == statePtr->freeBufferList) {
panic("NetUltraOutput: list screwup\n");
}
List_Remove(itemPtr);
buffer = (Address) itemPtr;
infoPtr->flags |= NET_ULTRA_INFO_STD_BUFFER;
if (rpc) {
int lastIndex;
/*
* This is a standard RPC packet with 4 parts --
* packet header, RPC header, RPC params, and data.
*/
size = 0;
lastIndex = scatterLength - 1;
for (i = 0; i < scatterLength; i++) {
size += scatterPtr[i].length;
}
Net_GatherCopy(scatterPtr, scatterLength, buffer);
} else {
if (netUltraDebug) {
printf("Copying data into DVMA space.\n");
}
Net_GatherCopy(scatterPtr, 1, buffer);
size = scatterPtr[0].length;
}
} else {
/*
* The data is already in DVMA space. It had better be contiguous!
*/
if (netUltraDebug) {
printf("Data is already in DVMA space.\n");
}
buffer = scatterPtr[0].bufAddr;
size = scatterPtr[0].length;
}
if (! DVMA_ADDRESS(buffer, statePtr)) {
buffer = BUFFER_TO_DVMA(buffer, statePtr);
}
hdrPtr->buffer = DVMA_TO_VME(buffer, statePtr);
hdrPtr->size = size;
} else {
hdrPtr->size = 0;
}
if (netUltraDebug) {
printf("NetUltraSendReq: hdrPtr->buffer = 0x%x, size = %d\n",
hdrPtr->buffer, hdrPtr->size);
}
#ifndef CLEAN
if (statePtr->flags & NET_ULTRA_STATE_STATS) {
if (hdrPtr->cmd == NET_ULTRA_DGRAM_SEND_REQ) {
statePtr->stats.packetsSent++;
statePtr->stats.bytesSent += hdrPtr->size;
statePtr->stats.sentHistogram[hdrPtr->size >> 10]++;
}
}
#endif
bcopy((char *) requestPtr, (char *) &xrbPtr->request, requestSize);
dmaPtr = &xrbPtr->dma;
if (hdrPtr->cmd == NET_ULTRA_DGRAM_SEND_REQ) {
dmaPtr->cmd = NET_ULTRA_DMA_CMD_XRB_DATA;
statePtr->numWritePending++;
#ifndef CLEAN
if (netUltraDebug) {
printf("NetUltraSendReq: number of pending writes = %d.\n",
statePtr->numWritePending);
}
#endif
if (statePtr->numWritePending > statePtr->maxWritePending) {
panic("NetUltraSendReq: too many writes.\n");
}
} else if (hdrPtr->cmd == NET_ULTRA_DGRAM_RECV_REQ) {
dmaPtr->cmd = NET_ULTRA_DMA_CMD_XRB;
statePtr->numReadPending++;
#ifndef CLEAN
if (netUltraDebug) {
printf("NetUltraSendReq: number of pending reads = %d.\n",
statePtr->numReadPending);
}
#endif
if (statePtr->numReadPending > statePtr->maxReadPending) {
panic("NetUltraSendReq: too many reads.\n");
}
} else {
dmaPtr->cmd = NET_ULTRA_DMA_CMD_XRB;
}
dmaPtr->id = 0;
dmaPtr->reference = 0;
dmaPtr->offset = 0;
dmaPtr->infoPtr = (NetUltraXRBInfo *) NIL;
dmaPtr->length = requestSize;
/*
* Set the filled field so the adapter will process the XRB.
*/
if (netUltraDebug) {
printf("NetUltraSendReq: xrbPtr = 0x%x\n", xrbPtr);
}
xrbPtr->filled = 1;
if (statePtr->nextToAdapterPtr == statePtr->lastToAdapterPtr) {
statePtr->nextToAdapterPtr = statePtr->firstToAdapterPtr;
} else {
statePtr->nextToAdapterPtr++;
}
/*
* Poke the adapter by setting the address register to 0. This
* tells it to look in the queue.
*/
*statePtr->intrReg = 0;
#ifndef CLEAN
if (netUltraDebug) {
printf("NetUltraSendReq: returning\n");
}
#endif
exit:
return status;
}
/*
*----------------------------------------------------------------------
*
* GetStatusString --
*
* Returns a string corresponding to the given status (status
* is a field in a NetUltraRequestHdr.
*
* Results:
* Ptr to string describing the status.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static char *
GetStatusString(status)
unsigned char status;
{
static char *statusMsg[] = {
"Unknown", /* 0 */
"OK", /* 1 */
"FAIL: invalid request", /* 2 */
"OK: EOM", /* 3 */
"FAIL: no resources", /* 4 */
"OK: decide", /* 5 */
"FAIL: unknown reference", /* 6 */
"OK: closed", /* 7 */
"FAIL: buffer too small", /* 8 */
"OK; withdrawn", /* 9 */
"FAIL: buffer too large", /* 10 */
"OK: reject connection", /* 11 */
"FAIL: illegal request", /* 12 */
"OK: connection request", /* 13 */
"FAIL: REM abort", /* 14 */
"OK: closing", /* 15 */
"FAIL: LOC timeout", /* 16 */
"OK: timed-out", /* 17 */
"FAIL: unknown connection class", /* 18 */
"OK: out of sequence", /* 19 */
"FAIL: duplicate request", /* 20 */
"Unknown", /* 21 */
"FAIL: connection rejected", /* 22 */
"Unknown", /* 23 */
"FAIL: negotiation failed", /* 24 */
"Unknown", /* 25 */
"FAIL: illegal address", /* 26 */
"Unknown", /* 27 */
"FAIL: network error", /* 28 */
"Unknown", /* 29 */
"FAIL: protocol error", /* 30 */
"Unknown", /* 31 */
"FAIL: illegal RB length", /* 32 */
"Unknown", /* 33 */
"FAIL: unknown SAP id", /* 34 */
"Unknown", /* 35 */
"FAIL: zero RB id", /* 36 */
"Unknown", /* 37 */
"FAIL: adapter down", /* 38 */
};
static int numStatusMsg = sizeof(statusMsg) / sizeof(char *);
if (status >= numStatusMsg) {
return "Unknown";
} else {
return statusMsg[status];
}
}
/*
*----------------------------------------------------------------------
*
* InitQueues --
*
* Initializes the XRB queues.
*
* Results:
* None.
*
* Side effects:
* Memory is allocated and mapped into DMA space if necessary.
*
*----------------------------------------------------------------------
*/
static void
InitQueues(statePtr)
NetUltraState *statePtr; /* State of the adapter. */
{
int size;
Address addr;
List_Links *itemPtr;
int i;
if (!(statePtr->queuesInit)) {
/*
* Allocate XRBs that go from the adapter to the host.
*/
size = sizeof(NetUltraXRB) * NET_ULTRA_NUM_TO_HOST;
addr = (Address) malloc(size);
addr = VmMach_DMAAlloc(size, (Address) addr);
if (addr == (Address) NIL) {
panic("NetUltraInit: unable to allocate DMA space.\n");
}
statePtr->firstToHostPtr = (NetUltraXRB *) addr;
/*
* Allocate XRBs that go from the host to the adapter.
*/
size = sizeof(NetUltraXRB) * NET_ULTRA_NUM_TO_ADAPTER;
addr = (Address) malloc(size);
addr = VmMach_DMAAlloc(size, (Address) addr);
if (addr == (Address) NIL) {
panic("NetUltraInit: unable to allocate DMA space.\n");
}
statePtr->firstToAdapterPtr = (NetUltraXRB *) addr;
statePtr->pendingXRBInfoList = &statePtr->pendingXRBInfoListHdr;
statePtr->freeXRBInfoList = &statePtr->freeXRBInfoListHdr;
List_Init(statePtr->pendingXRBInfoList);
List_Init(statePtr->freeXRBInfoList);
for (i = 0; i < NET_ULTRA_NUM_TO_ADAPTER + NET_ULTRA_NUM_TO_HOST; i++) {
itemPtr = (List_Links *) malloc(sizeof(NetUltraXRBInfo));
List_InitElement(itemPtr);
List_Insert(itemPtr, LIST_ATREAR(statePtr->freeXRBInfoList));
}
/*
* Allocate buffers in DVMA space for pending reads and writes.
*/
statePtr->maxReadPending = NET_ULTRA_PENDING_READS;
statePtr->numReadPending = 0;
statePtr->maxWritePending = NET_ULTRA_PENDING_WRITES;
statePtr->numWritePending = 0;
statePtr->numBuffers = statePtr->maxReadPending +
statePtr->maxWritePending;
statePtr->bufferSize = NET_ULTRA_MAX_BYTES;
size = statePtr->numBuffers * statePtr->bufferSize;
addr = (Address) malloc(size);
statePtr->buffers = addr;
addr = VmMach_DMAAlloc(size, (Address) addr);
statePtr->buffersDVMA = addr;
statePtr->freeBufferList = &statePtr->freeBufferListHdr;
statePtr->queuesInit = TRUE;
}
statePtr->lastToHostPtr = statePtr->firstToHostPtr +
NET_ULTRA_NUM_TO_HOST - 1;
statePtr->nextToHostPtr = statePtr->firstToHostPtr;
statePtr->lastToAdapterPtr = statePtr->firstToAdapterPtr +
NET_ULTRA_NUM_TO_ADAPTER - 1;
statePtr->nextToAdapterPtr = statePtr->firstToAdapterPtr;
size = sizeof(NetUltraXRB) * NET_ULTRA_NUM_TO_HOST;
bzero((char *) statePtr->firstToHostPtr, size);
size = sizeof(NetUltraXRB) * NET_ULTRA_NUM_TO_ADAPTER;
bzero((char *) statePtr->firstToAdapterPtr, size);
while (!List_IsEmpty(statePtr->pendingXRBInfoList)) {
itemPtr = List_First(statePtr->pendingXRBInfoList);
List_Remove(itemPtr);
List_Insert(itemPtr, LIST_ATREAR(statePtr->freeXRBInfoList));
}
bzero((char *) statePtr->buffers, statePtr->numBuffers *
statePtr->bufferSize);
List_Init(statePtr->freeBufferList);
for (i = 0; i < statePtr->numBuffers; i++) {
itemPtr = (List_Links *)
(statePtr->buffers + (i * statePtr->bufferSize));
List_InitElement(itemPtr);
List_Insert(itemPtr, LIST_ATREAR(statePtr->freeBufferList));
}
}
/*
*----------------------------------------------------------------------
*
* NetUltraPendingRead --
*
* Send a pending read to the adapter.
*
* Results:
* Standard Sprite return status.
*
* Side effects:
* A "read datagram" XRB is sent to the adapter.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraPendingRead(interPtr, size, buffer)
Net_Interface *interPtr; /* Interface to read from. */
int size; /* Size of the data buffer. */
Address buffer; /* Address of the buffer in DMA space */
{
NetUltraState *statePtr;
NetUltraRequest request;
NetUltraDatagramRequest *dgramReqPtr;
NetUltraRequestHdr *hdrPtr;
ReturnStatus status = SUCCESS;
Net_ScatterGather scatter;
statePtr = (NetUltraState *) interPtr->interfaceData;
if (!(statePtr->flags & NET_ULTRA_STATE_START)) {
printf("NetUltraPendingRead: adapter not started!\n");
return FAILURE;
}
#ifndef CLEAN
if (netUltraDebug) {
printf("NetUltraPendingRead: queuing a pending read.\n");
printf("Buffer size = %d, buffer = 0x%x\n", size, buffer);
}
#endif
statePtr = (NetUltraState *) interPtr->interfaceData;
bzero((char *) &request, sizeof(request));
dgramReqPtr = &request.dgram;
hdrPtr = &dgramReqPtr->hdr;
dgramReqPtr->remoteAddress = wildcardAddress;
dgramReqPtr->localAddress = wildcardAddress;
hdrPtr->cmd = NET_ULTRA_DGRAM_RECV_REQ;
/*
* Save room at the beginning of the buffer for the datagram request
* block. The higher-level software expects the packet header to
* proceed the packet (this should be fixed sometime).
*/
buffer += sizeof(NetUltraDatagramRequest);
size -= sizeof(NetUltraDatagramRequest);
scatter.bufAddr = buffer;
scatter.length = size;
status = NetUltraSendReq(statePtr, ReadDone, (ClientData) 0, FALSE,
1, &scatter, sizeof(NetUltraDatagramRequest), &request);
if (status != SUCCESS) {
printf("NetUltraPendingRead: could not send request to adapter\n");
}
#ifndef CLEAN
if (netUltraDebug) {
printf("NetUltraPendingRead: returning.\n");
}
#endif
return status;
}
/*
*----------------------------------------------------------------------
*
* ReadDone --
*
* This routine is called from the interrupt handler when a read
* request completes.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
static void
ReadDone(interPtr, infoPtr)
Net_Interface *interPtr; /* Interface. */
NetUltraXRBInfo *infoPtr; /* Info about XRB that completed. */
{
NetUltraXRB *xrbPtr;
NetUltraDatagramRequest *reqPtr;
NetUltraRequestHdr *hdrPtr;
NetUltraState *statePtr;
int size;
Address buffer = (Address) NIL;
ReturnStatus status = SUCCESS;
xrbPtr = infoPtr->xrbPtr;
reqPtr = &xrbPtr->request.dgram;
hdrPtr = &reqPtr->hdr;
statePtr = (NetUltraState *) interPtr->interfaceData;
if (!(hdrPtr->status & NET_ULTRA_STATUS_OK)) {
panic("ReadDone: read failed 0x%x (continuable)\n", hdrPtr->status);
} else {
#ifndef CLEAN
if (netUltraDebug) {
char local[32];
char remote[32];
printf("ReadDone: received a packet.\n");
*local = '\0';
*remote = '\0';
(void) Net_UltraAddrToString(&reqPtr->localAddress.address,
local);
(void) Net_UltraAddrToString(&reqPtr->remoteAddress.address,
remote);
printf("Local address: %s\n", local);
printf("Remote address: %s\n", remote);
printf("Data size = %d\n", hdrPtr->size);
if (hdrPtr->size > 0) {
printf("Data: %s\n", hdrPtr->buffer + VMMACH_DMA_START_ADDR);
}
}
#endif
/*
* Adjust size and start of buffer to account for the space
* for the request block.
*/
buffer = VME_TO_BUFFER(hdrPtr->buffer, statePtr) -
sizeof(NetUltraDatagramRequest);
size = hdrPtr->size + sizeof(NetUltraDatagramRequest);
if (statePtr->flags & NET_ULTRA_STATE_NORMAL) {
/*
* Copy the request block (packet header) to the start of the
* packet.
*/
*((NetUltraDatagramRequest *) buffer) = *reqPtr;
/*
* Release the lock around interface so that the RPC system
* can output a packet in response to this one. The XRB is
* still marked as filled, so the adapter won't overwrite it.
* Also the XRBinfo is not marked as pending, so the interrupt
* routine won't re-process the packet should it loop around
* the queue before Net_Input returns.
*/
MASTER_UNLOCK(&interPtr->mutex);
Net_Input(interPtr, buffer, size);
MASTER_LOCK(&interPtr->mutex);
} else if (statePtr->flags & NET_ULTRA_STATE_ECHO) {
Net_ScatterGather tmpScatter;
if (netUltraDebug) {
printf("ReadDone: returning datagram to sender.\n");
}
hdrPtr->cmd = NET_ULTRA_DGRAM_SEND_REQ;
hdrPtr->status = 0;
tmpScatter.bufAddr = BUFFER_TO_DVMA(buffer, statePtr);
tmpScatter.length = hdrPtr->size;
status = NetUltraSendReq(statePtr, EchoDone, (ClientData) NIL,
FALSE, 1, &tmpScatter,sizeof(NetUltraDatagramRequest),
(NetUltraRequest *) reqPtr);
if (status != SUCCESS) {
panic("ReadDone: unable to return datagram to sender.\n");
}
} else if (statePtr->flags & NET_ULTRA_STATE_DSND_TEST) {
Net_ScatterGather tmpScatter;
dsndCount--;
if (dsndCount > 0) {
if (netUltraDebug) {
printf("ReadDone: returning datagram to sender.\n");
}
hdrPtr->cmd = NET_ULTRA_DGRAM_SEND_REQ;
hdrPtr->status = 0;
tmpScatter.bufAddr = BUFFER_TO_DVMA(buffer, statePtr);
tmpScatter.length = hdrPtr->size;
status = NetUltraSendReq(statePtr, EchoDone, (ClientData) NIL,
FALSE, 1, &tmpScatter,
sizeof(NetUltraDatagramRequest),
(NetUltraRequest *) reqPtr);
if (status != SUCCESS) {
panic("ReadDone: unable to return datagram to sender.\n");
}
} else {
/*
* Notify the waiting process that the last datagram has
* arrived.
*/
Sync_Broadcast(&dsndTestDone);
}
} else if (statePtr->flags & NET_ULTRA_STATE_SINK) {
packetsSunk++;
}
}
statePtr->numReadPending--;
if (statePtr->numReadPending < 0) {
panic("ReadDone: number of pending reads < 0.\n");
}
/*
* This may introduce a deadlock if the queues are of size 1,
* since the XRB and info structures are
* not freed until this routine (ReadDone) returns, and
* NetUltraPendingRead needs to use these structures. If the queues
* are greater than 1 then NetUltraPendingRead may have to
* wait for an XRB to free up, but that should be ok.
*/
status = NetUltraPendingRead(interPtr, statePtr->bufferSize,
BUFFER_TO_DVMA(buffer,statePtr));
if (status != SUCCESS) {
printf("ReadDone: could not queue next pending read.\n");
}
#ifndef CLEAN
if (netUltraDebug) {
printf("ReadDone: returning.\n");
}
#endif
}
/*
*----------------------------------------------------------------------
*
* EchoDone --
*
* This routine is called when the write of a datagram that is
* being echoed back to the sender completes. All it does is
* decrement the number of pending writes.
*
* Results:
* None.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
/*ARGSUSED*/
static void
EchoDone(interPtr, infoPtr)
Net_Interface *interPtr; /* Interface. */
NetUltraXRBInfo *infoPtr; /* Info about XRB that completed. */
{
NetUltraState *statePtr;
statePtr = (NetUltraState *) interPtr->interfaceData;
statePtr->numWritePending--;
}
/*
*----------------------------------------------------------------------
*
* NetUltraSendDgram --
*
* This routine will send a datagram to the specified host. It
* is intended for debugging purposes.
*
* Results:
* None.
*
* Side effects:
* A write is queued to the adapter.
*
*----------------------------------------------------------------------
*/
static ReturnStatus
NetUltraSendDgram(interPtr, netAddressPtr, count, bufSize, buffer, timePtr)
Net_Interface *interPtr; /* Interface to send on. */
Net_Address *netAddressPtr; /* Host to send to. */
int count; /* Number of times to send
* datagram. */
int bufSize; /* Size of data buffer. */
Address buffer; /* Data to send. */
Time *timePtr; /* Place to store total
* time to send datagrams. */
{
NetUltraState *statePtr;
NetUltraRequest request;
NetUltraDatagramRequest *dgramReqPtr;
NetUltraRequestHdr *hdrPtr;
ReturnStatus status;
Timer_Ticks startTime;
Timer_Ticks endTime;
Timer_Ticks curTime;
NetUltraTraceInfo *tracePtr;
Net_ScatterGather scatter;
char *ptr;
MASTER_LOCK(&interPtr->mutex);
#ifndef CLEAN
if (netUltraDebug) {
char address[100];
(void) Net_AddrToString(netAddressPtr, address);
printf("NetUltraSendDgram: sending to %s\n", address);
}
#endif
statePtr = (NetUltraState *) interPtr->interfaceData;
if (!(statePtr->flags & NET_ULTRA_STATE_START)) {
printf("NetUltraSendDgram: adapter not started!\n");
status = FAILURE;
goto exit;
}
bzero((char *) &request, sizeof(request));
dgramReqPtr = &request.dgram;
hdrPtr = &dgramReqPtr->hdr;
dgramReqPtr->remoteAddress = wildcardAddress;
dgramReqPtr->remoteAddress.tsapSize = 2;
dgramReqPtr->remoteAddress.tsap[1] = 1;
dgramReqPtr->remoteAddress.address = netAddressPtr->address.ultra;
ptr = (char *) &dgramReqPtr->remoteAddress.address;
ptr[1] = 0x49;
ptr[6] = 0xfe;
dgramReqPtr->localAddress = wildcardAddress;
dgramReqPtr->localAddress.tsapSize = 2;
dgramReqPtr->localAddress.tsap[1] = 1;
dgramReqPtr->localAddress.address =
interPtr->netAddress[NET_PROTO_RAW].address.ultra;
ptr = (char *) &dgramReqPtr->localAddress.address;
ptr[1] = 0x49;
ptr[6] = 0xfe;
hdrPtr->cmd = NET_ULTRA_DGRAM_SEND_REQ;
scatter.bufAddr = buffer;
scatter.length = bufSize;
statePtr->flags |= NET_ULTRA_STATE_DSND_TEST;
statePtr->flags &= ~NET_ULTRA_STATE_NORMAL;
dsndCount = count;
#ifndef CLEAN
if (netUltraTrace) {
NEXT_TRACE(statePtr, &tracePtr);
tracePtr->event = DSND;
Timer_GetCurrentTicks(&curTime);
tracePtr->ticks = curTime;
}
#endif
Timer_GetCurrentTicks(&startTime);
status = NetUltraSendReq(statePtr, DgramSendDone, (ClientData) NIL,
FALSE, 1, &scatter, sizeof(NetUltraDatagramRequest), &request);
Sync_MasterWait(&(dsndTestDone), &(interPtr->mutex), FALSE);
Timer_GetCurrentTicks(&endTime);
#ifndef CLEAN
if (netUltraDebug) {
printf("NetUltraSendDgram: test done.\n");
}
#endif
statePtr->flags &= ~NET_ULTRA_STATE_DSND_TEST;
statePtr->flags |= NET_ULTRA_STATE_NORMAL;
Timer_SubtractTicks(endTime, startTime, &endTime);
Timer_TicksToTime(endTime, timePtr);
exit:
MASTER_UNLOCK(&interPtr->mutex);
return status;
}
/*
*----------------------------------------------------------------------
*
* DgramSendDone --
*
* Called by the interrupt handler when the datagram sent by
* NetUltraSendDgram is actually sent.
*
* Results:
* None.
*
* Side effects:
* The process waiting for the datagram to be sent is notified.
*
*----------------------------------------------------------------------
*/
static void
DgramSendDone(interPtr, infoPtr)
Net_Interface *interPtr; /* Interface. */
NetUltraXRBInfo *infoPtr; /* Info about XRB that completed. */
{
NetUltraXRB *xrbPtr;
NetUltraDatagramRequest *reqPtr;
NetUltraRequestHdr *hdrPtr;
xrbPtr = infoPtr->xrbPtr;
reqPtr = &xrbPtr->request.dgram;
hdrPtr = &reqPtr->hdr;
if (!(hdrPtr->status & NET_ULTRA_STATUS_OK)) {
panic("DgramSendDone: dgram send failed 0x%x\n", hdrPtr->status);
} else {
#ifndef CLEAN
if (netUltraDebug) {
printf("DgramSendDone: datagram sent ok\n");
}
#endif
}
((NetUltraState *) interPtr->interfaceData)->numWritePending--;
if (((NetUltraState *) interPtr->interfaceData)->numWritePending < 0) {
panic("DgramSendDone: number of pending writes < 0.\n");
}
if (infoPtr->doneData != (ClientData) NIL) {
Sync_Broadcast((Sync_Condition *) infoPtr->doneData);
}
#ifndef CLEAN
if (netUltraDebug) {
printf("DgramSendDone: returning.\n");
}
#endif
}
/*
*----------------------------------------------------------------------
*
* NetUltraOutput --
*
* Puts the outgoing packet into the queue to the adapter.
* Since the ultranet adapter does not to scatter/gather
* we have to get a free write buffer and copy the data
* into the buffer.
*
* Results:
* None.
*
* Side effects:
* The packet is put into the queue and the adapter is notified.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraOutput(interPtr, hdrPtr, scatterGatherPtr, scatterGatherLength, rpc,
statusPtr)
Net_Interface *interPtr; /* The interface to use. */
Address hdrPtr; /* Packet header. */
Net_ScatterGather *scatterGatherPtr; /* Scatter/gather elements.*/
int scatterGatherLength; /* Number of elements in
* scatter/gather list. */
Boolean rpc; /* Is this an RPC packet? */
ReturnStatus *statusPtr; /* Place to store status. */
{
NetUltraState *statePtr;
ReturnStatus status = SUCCESS;
Net_UltraHeader *ultraHdrPtr = (Net_UltraHeader *) hdrPtr;
statePtr = (NetUltraState *) interPtr->interfaceData;
if ((ultraHdrPtr->cmd != NET_ULTRA_DGRAM_SEND_REQ) &&
(ultraHdrPtr->cmd != 0)) {
printf("Invalid header to NetUltraOutput.\n");
return FAILURE;
}
/*
* If the cmd is 0 then the packet is from the network device.
*/
if (ultraHdrPtr->cmd == 0) {
ultraHdrPtr->cmd = NET_ULTRA_DGRAM_SEND_REQ;
}
MASTER_LOCK(&interPtr->mutex);
if (netUltraDebug) {
char address[100];
(void) Net_UltraAddrToString(&ultraHdrPtr->remoteAddress.address,
address);
printf("NetUltraOutput: sending to %s\n", address);
}
status = NetUltraSendReq(statePtr, OutputDone,
(ClientData) statusPtr, rpc, scatterGatherLength,
scatterGatherPtr, sizeof(Net_UltraHeader),
(NetUltraRequest *) ultraHdrPtr);
if (status != SUCCESS) {
printf("NetUltraOutput: packet not sent\n");
}
MASTER_UNLOCK(&interPtr->mutex);
return status;
}
/*
*----------------------------------------------------------------------
*
* OutputDone --
*
* This routine is called by the interrupt handler when a packet
* sent by NetUltraOutput completes.
*
* Results:
* None.
*
* Side effects:
* The write buffer associated with the command is added to
* the list of free write buffers.
*
*----------------------------------------------------------------------
*/
static void
OutputDone(interPtr, infoPtr)
Net_Interface *interPtr; /* Interface. */
NetUltraXRBInfo *infoPtr; /* Info about XRB that completed. */
{
NetUltraRequestHdr *hdrPtr;
NetUltraState *statePtr;
ReturnStatus *statusPtr;
ReturnStatus status = SUCCESS;
hdrPtr = &(infoPtr->xrbPtr->request.dgram.hdr);
statusPtr = (ReturnStatus *) infoPtr->doneData;
statePtr = (NetUltraState *) interPtr->interfaceData;
if (!(hdrPtr->status & NET_ULTRA_STATUS_OK)) {
printf("Warning: OutputDone: write failed 0x%x\n", hdrPtr->status);
status = FAILURE;
}
#ifndef CLEAN
if (netUltraDebug) {
printf("OutputDone: packet sent\n");
}
#endif
statePtr->numWritePending--;
if (statePtr->numWritePending < 0) {
panic("OutputDone: number of pending writes < 0.\n");
}
/*
* Return status to the waiting process.
*/
if (statusPtr != (ReturnStatus *) NIL) {
*statusPtr = status;
}
/*
* Wakeup any process waiting for the packet to be sent.
*/
infoPtr->scatterPtr->done = TRUE;
if (infoPtr->scatterPtr->mutexPtr != (Sync_Semaphore *) NIL) {
NetOutputWakeup(infoPtr->scatterPtr->mutexPtr);
}
}
/*
*----------------------------------------------------------------------
*
* NetUltraSource --
*
* This routine will send a stream of datagrams to the specified host.
*
* Results:
* None.
*
* Side effects:
* A write is queued to the adapter.
*
*----------------------------------------------------------------------
*/
static ReturnStatus
NetUltraSource(interPtr, netAddressPtr, count, bufSize, buffer, timePtr)
Net_Interface *interPtr; /* Interface to send on. */
Net_Address *netAddressPtr; /* Host to send to. */
int count; /* Number of times to send
* datagram. */
int bufSize; /* Size of data buffer. */
Address buffer; /* Data to send. */
Time *timePtr; /* Place to store total
* time to send datagrams. */
{
NetUltraState *statePtr;
NetUltraRequest request;
NetUltraDatagramRequest *dgramReqPtr;
NetUltraRequestHdr *hdrPtr;
ReturnStatus status = SUCCESS;
List_Links *itemPtr;
Timer_Ticks startTime;
Timer_Ticks endTime;
Timer_Ticks curTime;
NetUltraTraceInfo *tracePtr;
Net_ScatterGather scatter;
char *ptr;
MASTER_LOCK(&interPtr->mutex);
#ifndef CLEAN
if (netUltraDebug) {
char address[100];
(void) Net_AddrToString(netAddressPtr, address);
printf("NetUltraSendDgram: sending to %s\n", address);
}
#endif
statePtr = (NetUltraState *) interPtr->interfaceData;
if (!(statePtr->flags & NET_ULTRA_STATE_START)) {
printf("NetUltraSendDgram: adapter not started!\n");
status = FAILURE;
goto exit;
}
bzero((char *) &request, sizeof(request));
dgramReqPtr = &request.dgram;
hdrPtr = &dgramReqPtr->hdr;
dgramReqPtr->remoteAddress = wildcardAddress;
dgramReqPtr->remoteAddress.tsapSize = 2;
dgramReqPtr->remoteAddress.tsap[1] = 1;
dgramReqPtr->remoteAddress.address = netAddressPtr->address.ultra;
ptr = (char *) &dgramReqPtr->remoteAddress.address;
ptr[1] = 0x49;
ptr[6] = 0xfe;
dgramReqPtr->localAddress = wildcardAddress;
dgramReqPtr->localAddress.tsapSize = 2;
dgramReqPtr->localAddress.tsap[1] = 1;
dgramReqPtr->localAddress.address =
interPtr->netAddress[NET_PROTO_RAW].address.ultra;
ptr = (char *) &dgramReqPtr->localAddress.address;
ptr[1] = 0x49;
ptr[6] = 0xfe;
hdrPtr->cmd = NET_ULTRA_DGRAM_SEND_REQ;
Timer_GetCurrentTicks(&startTime);
while(count > 0) {
count--;
while(List_IsEmpty(statePtr->freeBufferList)) {
int signal;
statePtr->bufferAvail.waiting = TRUE;
signal = Sync_SlowMasterWait((unsigned int) &statePtr->bufferAvail,
&interPtr->mutex, TRUE);
if (signal) {
status = GEN_ABORTED_BY_SIGNAL;
goto exit;
}
}
itemPtr = List_First(statePtr->freeBufferList);
if (itemPtr == statePtr->freeBufferList) {
panic("NetUltraSendDgram: list screwup\n");
}
List_Remove(itemPtr);
if (buffer != (Address) NIL) {
bcopy((char *) buffer, (char *) itemPtr, bufSize);
}
dsndCount = count;
#ifndef CLEAN
if (netUltraTrace) {
NEXT_TRACE(statePtr, &tracePtr);
tracePtr->event = DSND_STREAM;
Timer_GetCurrentTicks(&curTime);
tracePtr->ticks = curTime;
}
#endif
scatter.bufAddr = BUFFER_TO_DVMA(itemPtr, statePtr);
scatter.length = bufSize;
status = NetUltraSendReq(statePtr, SourceDone,
(ClientData) NIL, FALSE, 1, &scatter,
sizeof(NetUltraDatagramRequest), &request);
}
Timer_GetCurrentTicks(&endTime);
Timer_SubtractTicks(endTime, startTime, &endTime);
Timer_TicksToTime(endTime, timePtr);
exit:
MASTER_UNLOCK(&interPtr->mutex);
return status;
}
/*
*----------------------------------------------------------------------
*
* SourceDone --
*
* This routine is called by the interrupt handler when a packet
* sent by NetUltraSource completes.
*
* Results:
* None.
*
* Side effects:
* The write buffer associated with the command is added to
* the list of free write buffers.
*
*----------------------------------------------------------------------
*/
static void
SourceDone(interPtr, infoPtr)
Net_Interface *interPtr; /* Interface. */
NetUltraXRBInfo *infoPtr; /* Info about XRB that completed. */
{
NetUltraRequestHdr *hdrPtr;
NetUltraState *statePtr;
List_Links *itemPtr;
hdrPtr = &(infoPtr->xrbPtr->request.dgram.hdr);
statePtr = (NetUltraState *) interPtr->interfaceData;
if (!(hdrPtr->status & NET_ULTRA_STATUS_OK)) {
panic("SourceDone: write failed 0x%x (continuable)\n", hdrPtr->status);
} else {
#ifndef CLEAN
if (netUltraDebug) {
printf("SourceDone: packet sent\n");
}
#endif
statePtr->numWritePending--;
if (statePtr->numWritePending < 0) {
panic("SourceDone: number of pending writes < 0.\n");
}
/*
* Free up the write buffer.
*/
itemPtr = (List_Links *) VME_TO_BUFFER(hdrPtr->buffer,statePtr);
List_Insert(itemPtr, LIST_ATREAR(statePtr->freeBufferList));
if (statePtr->bufferAvail.waiting == TRUE) {
Sync_Broadcast(&statePtr->bufferAvail);
}
}
}
/*
*----------------------------------------------------------------------
*
* NetUltraGetStats --
*
* Return the statistics for the interface.
*
* Results:
* A pointer to the statistics structure.
*
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
ReturnStatus
NetUltraGetStats(interPtr, statPtr)
Net_Interface *interPtr; /* Current interface. */
Net_Stats *statPtr; /* Statistics to return. */
{
NetUltraState *statePtr;
statePtr = (NetUltraState *) interPtr->interfaceData;
MASTER_LOCK(&interPtr->mutex);
statPtr->ultra = statePtr->stats;
MASTER_UNLOCK(&interPtr->mutex);
return SUCCESS;
}